package top.fangwenmagician.killfire.entity;

import net.fabricmc.api.EnvType;
import net.fabricmc.api.Environment;
import net.minecraft.block.Block;
import net.minecraft.block.Blocks;
import net.minecraft.block.entity.BlockEntity;
import net.minecraft.entity.Entity;
import net.minecraft.entity.EntityType;
import net.minecraft.entity.LivingEntity;
import net.minecraft.entity.damage.DamageSource;
import net.minecraft.entity.effect.StatusEffectInstance;
import net.minecraft.entity.effect.StatusEffects;
import net.minecraft.entity.mob.BlazeEntity;
import net.minecraft.entity.projectile.thrown.ThrownItemEntity;
import net.minecraft.item.ItemStack;
import net.minecraft.particle.ItemStackParticleEffect;
import net.minecraft.particle.ParticleEffect;
import net.minecraft.particle.ParticleTypes;
import net.minecraft.server.command.FillCommand;
import net.minecraft.server.world.ServerWorld;
import net.minecraft.sound.SoundEvents;
import net.minecraft.util.Clearable;
import net.minecraft.util.hit.EntityHitResult;
import net.minecraft.util.hit.HitResult;
import net.minecraft.util.math.BlockBox;
import net.minecraft.util.math.BlockPos;
import net.minecraft.util.math.Vec3d;
import net.minecraft.util.math.Vec3i;
import net.minecraft.world.World;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import java.util.ArrayList;

public abstract class IceHeartEntity extends ThrownItemEntity {
    private final Logger logger = LoggerFactory.getLogger(IceHeartEntity.class);

    public IceHeartEntity(EntityType<? extends ThrownItemEntity> entityType, World world) {
        super(entityType, world);
    }

    public IceHeartEntity(EntityType<? extends ThrownItemEntity> entityType, double d, double e, double f, World world) {
        super(entityType, d, e, f, world);
    }

    public IceHeartEntity(EntityType<? extends ThrownItemEntity> entityType, LivingEntity livingEntity, World world) {
        super(entityType, livingEntity, world);
    }

    @Environment(EnvType.CLIENT)
    public ParticleEffect getParticleParameters() { // Not entirely sure, but probably has do to with the snowball's particles. (OPTIONAL)
        ItemStack itemStack = this.getItem();
        return itemStack.isEmpty() ? ParticleTypes.ITEM_SNOWBALL : new ItemStackParticleEffect(ParticleTypes.ITEM, itemStack);
    }

    @Environment(EnvType.CLIENT)
    public void handleStatus(byte status) { // Also not entirely sure, but probably also has to do with the particles. This method (as well as the previous one) are optional, so if you don't understand, don't include this one.
        if (status == 3) {
            ParticleEffect particleEffect = this.getParticleParameters();

            for (int i = 0; i < 8; ++i) {
                this.world.addParticle(particleEffect, this.getX(), this.getY(), this.getZ(), 0.0D, 0.0D, 0.0D);
            }
        }

    }

    public void onEntityHit(EntityHitResult entityHitResult) { // called on entity hit.
        super.onEntityHit(entityHitResult);
        Entity entity = entityHitResult.getEntity(); // sets a new Entity instance as the EntityHitResult (victim)
        int i = entity instanceof BlazeEntity ? 3 : 0; // sets i to 3 if the Entity instance is an instance of BlazeEntity
        entity.damage(DamageSource.thrownProjectile(this, this.getOwner()), (float) i); // deals damage

        if (entity instanceof LivingEntity livingEntity) { // checks if entity is an instance of LivingEntity (meaning it is not a boat or minecart)
            livingEntity.addStatusEffect((new StatusEffectInstance(StatusEffects.BLINDNESS, 20 * 3, 0))); // applies a status effect
            livingEntity.addStatusEffect((new StatusEffectInstance(StatusEffects.SLOWNESS, 20 * 3, 2))); // applies a status effect
//            livingEntity.addStatusEffect((new StatusEffectInstance(StatusEffects.POISON, 20 * 3, 1))); // applies a status effect
            livingEntity.playSound(SoundEvents.AMBIENT_CAVE, 2F, 1F); // plays a sound for the entity hit only
        }
    }

    /**
     * 将以落点为中心，16*16*16区域内的火焰对象替换为空气<br />
     * 参照{@link FillCommand}
     *
     * @param hitResult 落点
     */
    public void onCollision(HitResult hitResult) { // called on collision with a block
        super.onCollision(hitResult);
        try {
            Vec3d pos = hitResult.getPos();
            BlockBox blockBox = getBlockBox(new Vec3i(pos.x, pos.y, pos.z));
            ArrayList<BlockPos> list = new ArrayList<>();
            for (BlockPos blockPos : BlockPos.iterate(blockBox.getMinX(), blockBox.getMinY(), blockBox.getMinZ(),
                    blockBox.getMaxX(), blockBox.getMaxY(), blockBox.getMaxZ())) {
                if (Blocks.FIRE.getName().equals(world.getBlockState(blockPos).getBlock().getName())) {
                    BlockEntity blockEntity = world.getBlockEntity(blockPos);
                    Clearable.clear(blockEntity);
                    if (!world.setBlockState(blockPos, Blocks.AIR.getDefaultState(), Block.NOTIFY_LISTENERS)) continue;
                    list.add(blockPos.toImmutable());
                }
            }
            for (BlockPos blockPos : list) {
                Block block2 = world.getBlockState(blockPos).getBlock();
                world.updateNeighbors(blockPos, block2);
            }
            if (!this.world.isClient) {
                this.world.sendEntityStatus(this, (byte) 3);
                this.kill();
            }
        } catch (NullPointerException e) {
            logger.error("ServerWorld获取失败", e);
        }

    }

    /**
     * 获取作用范围{@link  BlockBox}对象
     *
     * @param hitResultPos 落点
     * @return {@link  BlockBox}对象
     */
    protected abstract BlockBox getBlockBox(Vec3i hitResultPos);


}
